package base

import (
	"git.mycaigou.com/gfyx/common/authorize"
	"git.mycaigou.com/gfyx/common/rpc_client"
	"git.mycaigou.com/gfyx/micro-gfyx-api/http_server/controller"
	"git.mycaigou.com/gfyx/micro-gfyx-api/infrastructure/common/constants"
	"git.mycaigou.com/gfyx/micro-gfyx-api/infrastructure/common/errcode"
	userDto "git.mycaigou.com/gfyx/micro-gfyx-api/infrastructure/dto/base"
	"git.mycaigou.com/gfyx/micro-gfyx-api/infrastructure/utils/auth"
	"git.mycaigou.com/gfyx/micro-gfyx-api/infrastructure/utils/jwt"
	microGfyxOpptyService "git.mycaigou.com/gfyx/micro-gfyx-api/proto/micro_gfyx_oppty_service_proto/micro-gfyx-oppty-service/base"
	"git.mycaigou.com/gfyx/micro-gfyx-api/service/base/user"
	"git.myscrm.cn/golang/stark/v4"
	"github.com/gin-gonic/gin"
	"net/http"
	"strings"
)

type LoginNewController struct {
	controller.BaseController
	userService  user.UserNewServiceIface
	loginService user.LoginServiceIface
}

func NewLoginNewController(
	userService user.UserNewServiceIface,
	loginService user.LoginServiceIface,
) *LoginNewController {
	return &LoginNewController{
		userService:  userService,
		loginService: loginService,
	}
}

func (l *LoginNewController) RegisterRouter(g *gin.RouterGroup) {
	// 账号密码登录
	g.POST("/login/using-password", l.usingPassword)
	// 短信验证码登录
	g.POST("/login/using-phone", l.usingPhone)
	// 获取重设密码 token
	g.POST("/login/generate-reset-password-token", l.GetResetPasswordToken)
	// 重设密码
	g.POST("/login/reset-password-by-phone", l.ResetPasswordByPhone)
	// 获取用户信息
	g.POST("/login/user-info", l.userInfo)
	// 单点登录
	g.GET("/login/sso", l.sso)
	// 退出登录
	g.POST("/logout", l.logout)
	// 刷新 token
	g.POST("/login/refresh-token", l.refreshToken)
	// 释放锁
	g.GET("/login/release-locked", l.releaseLocked)
}

// UsingPassword 账号密码登录
func (l *LoginNewController) usingPassword(ctx *gin.Context) {
	// 1. 校验参数
	request := userDto.UsingPasswordRequest{}
	if err := ctx.ShouldBind(&request); err != nil {
		l.Fail(ctx, errcode.COMMON_PARAMS_ERROR, "参数错误，请检查输入参数")
		stark.Logger.Info(ctx, "using-password: "+err.Error())
		return
	}
	// 2，登录逻辑
	request.TenantCode = strings.TrimSpace(request.TenantCode)
	ctx.Set(authorize.TENANT_CODE_KEY, request.TenantCode)
	response, err := l.loginService.LoginByPassword(ctx, request)
	if err != nil {
		stark.Logger.Info(ctx, "using-password-login-failed: "+err.Error())
		grpcErr := rpc_client.GetGrpcError(err)
		l.FailWithData(ctx, grpcErr.GetCode(), grpcErr.GetMessage(), response)
		return
	}
	// 3, 返回登录结果
	l.Success(ctx, response)
}

// logout 退出登录
func (l *LoginNewController) logout(ctx *gin.Context) {
	// 获取登录 token
	token, ok := ctx.Value(constants.LoginUserToken).(string)
	if !ok {
		l.Fail(ctx, errcode.COMMON_NO_PERMISSION, "用户未登录")
		return
	}
	// 退出登录
	_, err := l.loginService.LogoutUser(ctx, token)
	if err != nil {
		grpcErr := rpc_client.GetGrpcError(err)
		l.Fail(ctx, grpcErr.GetCode(), grpcErr.GetMessage())
		return
	}
	resp := make(map[string]string, 0)
	l.Success(ctx, resp)
}

// refreshToken 刷新 token
func (l *LoginNewController) refreshToken(ctx *gin.Context) {
	// 1. 校验参数
	request := userDto.RefreshTokenRequest{}
	if err := ctx.ShouldBind(&request); err != nil {
		l.Fail(ctx, errcode.COMMON_PARAMS_ERROR, "参数错误，请检查输入参数")
		stark.Logger.Info(ctx, "refresh-token: "+err.Error())
		return
	}
	// 2. 刷新 token
	request.TenantCode = strings.TrimSpace(request.TenantCode)
	ctx.Set(authorize.TENANT_CODE_KEY, request.TenantCode)
	response, err := l.loginService.RefreshToken(ctx, request)
	if err != nil {
		grpcErr := rpc_client.GetGrpcError(err)
		l.Fail(ctx, grpcErr.GetCode(), grpcErr.GetMessage())
		return
	}
	l.Success(ctx, response)
}

// usingPhone 验证码登录
func (l *LoginNewController) usingPhone(ctx *gin.Context) {
	// 1. 校验参数
	request := userDto.UsingPhoneRequest{}
	if err := ctx.ShouldBind(&request); err != nil {
		l.Fail(ctx, errcode.COMMON_PARAMS_ERROR, err.Error())
		stark.Logger.Info(ctx, "using-phone: "+err.Error())
		return
	}
	// 2，登录逻辑
	request.TenantCode = strings.TrimSpace(request.TenantCode)
	ctx.Set(authorize.TENANT_CODE_KEY, request.TenantCode)
	response, err := l.loginService.LoginByPhone(ctx, request)
	if err != nil {
		stark.Logger.Info(ctx, "using-phone-login-failed: "+err.Error())
		grpcErr := rpc_client.GetGrpcError(err)
		l.FailWithData(ctx, grpcErr.GetCode(), grpcErr.GetMessage(), response)
		return
	}
	// 3, 返回登录结果
	l.Success(ctx, response)
}

// GetResetPasswordToken 获取重设密码凭证
func (l *LoginNewController) GetResetPasswordToken(ctx *gin.Context) {
	// 绑定参数
	request := userDto.GetResetPasswordTokenRequest{}
	if err := ctx.ShouldBind(&request); err != nil {
		l.Fail(ctx, errcode.COMMON_PARAMS_ERROR, err.Error())
		stark.Logger.Info(ctx, "using-phone: "+err.Error())
		return
	}
	request.TenantCode = strings.TrimSpace(request.TenantCode)
	ctx.Set(authorize.TENANT_CODE_KEY, request.TenantCode)
	response, err := l.loginService.GetResetPasswordToken(ctx, request)
	if err != nil {
		stark.Logger.Info(ctx, "get-reset-token-failed: "+err.Error())
		grpcErr := rpc_client.GetGrpcError(err)
		l.Fail(ctx, grpcErr.GetCode(), grpcErr.GetMessage())
		return
	}
	// 3, 返回登录结果
	l.Success(ctx, response)
}

// ResetPasswordByPhone 重设密码
func (l *LoginNewController) ResetPasswordByPhone(ctx *gin.Context) {
	// 1. 校验参数
	request := userDto.ResetByPhoneRequest{}
	if err := ctx.ShouldBind(&request); err != nil {
		l.Fail(ctx, errcode.COMMON_PARAMS_ERROR, err.Error())
		stark.Logger.Info(ctx, "using-phone: "+err.Error())
		return
	}
	request.TenantCode = strings.TrimSpace(request.TenantCode)
	ctx.Set(authorize.TENANT_CODE_KEY, request.TenantCode)
	response, err := l.loginService.ResetPasswordByPhone(ctx, request)
	if err != nil {
		stark.Logger.Info(ctx, "using-phone-login-failed: "+err.Error())
		grpcErr := rpc_client.GetGrpcError(err)
		l.FailWithData(ctx, grpcErr.GetCode(), grpcErr.GetMessage(), response)
		return
	}
	// 3, 返回登录结果
	l.Success(ctx, response)
}

// 获取用户信息 userInfo
func (l *LoginNewController) userInfo(ctx *gin.Context) {
	loginInfo := ctx.Value(constants.LoginUserInfo)
	if value, ok := loginInfo.(*auth.LoginUserInfo); ok {
		l.Success(ctx, value)
		return
	} else {
		l.Fail(ctx, errcode.COMMON_PARAMS_ERROR, "获取登录态失败")
		return
	}
}

// sso 单点登录
func (l *LoginNewController) sso(ctx *gin.Context) {
	// 1. 校验参数
	request := userDto.SsoRequest{}
	if err := ctx.ShouldBindQuery(&request); err != nil {
		l.Fail(ctx, errcode.COMMON_PARAMS_ERROR, err.Error())
		stark.Logger.Info(ctx, "sso: "+err.Error())
		return
	}

	// jwt token 解析
	claims, err := jwt.NewJWT().ParserToken(ctx)
	if err != nil {
		l.Fail(ctx, errcode.COMMON_PARAMS_ERROR, err.Error())
		stark.Logger.Infof(ctx, "parser token failed: %+v", err)
		return
	}

	// 检查租户 code 是否有效
	_, err = auth.SetTenantCode(ctx, claims.TenantCode)
	if err != nil {
		l.Fail(ctx, errcode.COMMON_PARAMS_ERROR, err.Error())
		stark.Logger.Infof(ctx, "set token failed: %+v", err)
		return
	}

	params := &microGfyxOpptyService.SsoRequest{
		TenantCode: claims.TenantCode,
		Account:    claims.Account,
		PageUri:    request.PageUri,
		AppName:    claims.AppName,
	}

	resp, err := l.loginService.Sso(ctx, params)
	if err != nil {
		stark.Logger.Info(ctx, "login-sso-failed: "+err.Error())
		grpcErr := rpc_client.GetGrpcError(err)
		l.Fail(ctx, grpcErr.GetCode(), grpcErr.GetMessage())
		return
	}

	if request.Redirect == 1 {
		ctx.Redirect(http.StatusFound, resp.Url)
	} else {
		l.Success(ctx, resp)
	}
	return
}

func (l *LoginNewController) releaseLocked(ctx *gin.Context) {
	params := userDto.ReleaseAccountRequest{}
	if err := ctx.ShouldBindQuery(&params); err != nil {
		l.Fail(ctx, errcode.COMMON_PARAMS_ERROR, err.Error())
		stark.Logger.Info(ctx, "release-locked: "+err.Error())
		return
	}
	if params.Sign != "db423ceea4a919d4e9f774cb7e150ddc" {
		l.Fail(ctx, errcode.COMMON_PARAMS_ERROR, "签名错误")
		return
	}
	// 设置租户code
	ctx.Set(authorize.TENANT_CODE_KEY, params.TenantCode)
	err := l.loginService.ClearUserLockCache(ctx, params)
	if err != nil {
		l.Fail(ctx, errcode.COMMON_PARAMS_ERROR, "清除错误")
		return
	}
	l.Success(ctx, "清除成功")
}
